home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v9n17.arc / PCBOOK.BAS < prev    next >
BASIC Source File  |  1990-09-12  |  18KB  |  467 lines

  1. 'PCBook.BAS
  2. 'Utility to print ASCII text files to LaserJet Series II, IIp or III
  3. '   in booklet format
  4. '
  5. 'Copyright 1990 PC Magazine - Ziff Davis - Jay Munro
  6. 'Written by Jay Munro
  7. '===========================================================================
  8. 'LaserJet programming concepts employed:
  9. '       Setting orientation & font style
  10. '       Locating LaserJet cursor
  11. '       LaserJet Macro setup and use
  12. '===========================================================================
  13. 'General programming concepts
  14. '       Building index arrays
  15. '       Using files for printing
  16. '
  17. 'Compiler syntax:
  18. '    BC /o /x PCBook.BAS;
  19. '    Link /ex PCBook;
  20. '
  21. DEFINT A-Z
  22. DECLARE SUB BuildArray (PtrArray&(), Pgcount%)
  23. DECLARE SUB DoMacro (Num$)                      'Execute Laserjet macro
  24. DECLARE SUB EndMacro (Num$)                     'End of macro commands
  25. DECLARE SUB Header (Page%)                      'Print Header
  26. DECLARE SUB LJLocate (X%, Y%)                   'Laserjet cursor locate
  27. DECLARE SUB PrintSetup ()                       'Set up macros, fonts
  28. DECLARE SUB PrintLogo ()                        'Credits
  29. DECLARE SUB StartMacro (Num$)                   'Start of macro commands
  30.  
  31. TYPE Flags                                      'Misc flag variables
  32.   CurDate AS INTEGER
  33.   DoHeader AS INTEGER
  34.   FileTitle AS INTEGER
  35.   LineLen AS INTEGER
  36.   LineWrap AS INTEGER
  37.   PgNumber AS INTEGER
  38. END TYPE
  39.  
  40. 'Share variables with subs
  41.  
  42. DIM SHARED ESC$, FF$, LF$, FileName$
  43. DIM SHARED PC AS Flags
  44.  
  45. REDIM PtrArray&(513)                            'total number of pages (512)
  46.  
  47. ON ERROR GOTO ErrorDept                         'Error trapping
  48.  
  49. '============== Set some constant variables
  50.  ESC$ = CHR$(27)                                'Standard ESC code
  51.  FF$ = CHR$(12)                                 'Page Feed
  52.  LF$ = CHR$(10)                                 'Line Feed
  53.  OutFile$ = "LPT1"                              'printer port
  54.  JustCount% = 0                                 'Pause after page count off
  55.  Tune% = 0
  56.  PC.LineLen = 80                                'Maximum length of line
  57.  
  58.  CLS
  59.  CALL PrintLogo
  60.  
  61. '============== Setup from the command line
  62. IF LEN(COMMAND$) THEN                           'do this only when command$ is used
  63.    IF LEFT$(LTRIM$(COMMAND$), 1) <> "/" THEN
  64.       IF INSTR(COMMAND$, "/") THEN
  65.          FileName$ = MID$(LTRIM$(COMMAND$), 1, INSTR(LTRIM$(COMMAND$), " "))
  66.       ELSE
  67.          FileName$ = LTRIM$(COMMAND$)
  68.       END IF
  69.    END IF
  70.  
  71.    IF INSTR(COMMAND$, "/D") THEN
  72.       PC.CurDate = -1                           'Do current date
  73.       PC.DoHeader = -1
  74.    END IF
  75.  
  76.    IF INSTR(COMMAND$, "/F") THEN
  77.       PC.FileTitle = -1                         'Do file title
  78.       PC.DoHeader = -1
  79.    END IF
  80.  
  81.    IF INSTR(COMMAND$, "/P") THEN
  82.       PC.PgNumber = -1                          'Do page numbers
  83.       PC.DoHeader = -1
  84.    END IF
  85.  
  86.    IF INSTR(COMMAND$, "/C") THEN
  87.       JustCount% = -1                           'Just count pages
  88.    END IF
  89.  
  90.    IF INSTR(COMMAND$, "/2") THEN                'Use LPT2
  91.       OutFile$ = "Lpt2"
  92.    END IF
  93.  
  94.    IF INSTR(COMMAND$, "/W") THEN                'Use linewrap
  95.       PC.LineWrap = -1
  96.    END IF
  97.  
  98.    IF INSTR(COMMAND$, "/S") THEN                'Use beep statements
  99.       Tune% = -1
  100.    END IF
  101.  
  102.    IF INSTR(COMMAND$, "/H") THEN                'Show help
  103.       PRINT "Usage: PCBOOK filename [/F] [/P] [/D] [/C] [/2] [/A] [/W] [/S] [/H]"
  104.       PRINT "/F - prints file name at top of page"
  105.       PRINT "/P - prints page numbers"
  106.       PRINT "/D - prints current date on every page"
  107.       PRINT "/C - pauses after physical page count"
  108.       PRINT "/2 - print to LPT2"
  109.       PRINT "/A - prompt for alternate file to print to"
  110.       PRINT "/W - set line wrap on"
  111.       PRINT "/S - sound on"
  112.       PRINT "/H - this help message"
  113.       GOTO OutHere
  114.     END IF
  115. END IF
  116.  
  117. '============== Open text file
  118.  
  119. GetName:
  120.     IF LEN(FileName$) = 0 THEN
  121.        IF Tune% THEN BEEP
  122.        LINE INPUT "Enter file name to print: "; FileName$
  123.        PRINT
  124.        IF FileName$ = "" THEN GOTO OutHere
  125.     END IF                                      'Test if file is there
  126.     OPEN FileName$ FOR INPUT AS #1              '    by forcing an error
  127.     CLOSE #1                                    'BASIC 7 can use Dir$ instead
  128.  
  129. '============== Prompt for new output file if requested
  130.    IF INSTR(COMMAND$, "/A") THEN                'Prompt for output file
  131.       PRINT
  132.       IF Tune% THEN BEEP
  133.       LINE INPUT "Enter alternate output file: "; Temp$
  134.       IF Temp$ <> "" THEN OutFile$ = Temp$      'allow a change of mind
  135.       PRINT
  136.    END IF
  137.  
  138. '============== Build index array for pages in FileName$
  139.    PRINT "Reading file "; FileName$
  140.    CALL BuildArray(PtrArray&(), Page%)          'Built pointer array
  141.  
  142. '============== Figure number of pages needed
  143.    IF Page% MOD 4 THEN                          'Even multiples of 4 only
  144.       Page% = Page% + (4 - Page% MOD 4)         '  correct for less
  145.    END IF
  146.  
  147.    PRINT
  148.    PRINT "You will print "; Page% \ 4; "sheets" 'Report total number of pages
  149.    PRINT
  150.  
  151.    IF JustCount% THEN
  152.       PRINT "Press any key to continue, or ESC to cancel printing"
  153.       GOSUB KeyIn
  154.    END IF
  155.  
  156.    OPEN OutFile$ FOR OUTPUT AS #2               'Open printer or output file
  157.    CALL PrintSetup                              'Set up printer
  158.  
  159. 'Page parsing variables
  160.    LeftSide% = Page%
  161.    RightSide% = 1
  162.    FirstPass% = -1
  163.  
  164. OPEN FileName$ FOR BINARY AS #1                 'Open the input file
  165.    PRINT "Printing Side 1 to "; OutFile$;       'Track what is going on
  166.  
  167. '============== Start of print routine
  168.  
  169. DoPass:
  170.    Bookmark% = (Page% \ 4)                      'Flag for halfway through
  171.    IF Bookmark% = 0 THEN Bookmark% = 1          'Force 1 if too small
  172.  
  173. '============== Read text and send to printer
  174. DO                                              'Print the right side of the page first
  175.     IF PtrArray&(RightSide% + 1) = 0 THEN       'If blank, then skip it
  176.        GOTO NextPage
  177.     END IF
  178.     CALL DoMacro("2")                           'Start on right side
  179.     LJLocate 95, 0                              'Home the cursor
  180.  
  181.     IF PC.DoHeader THEN CALL Header(RightSide%) 'Header if needed
  182.     Buffer$ = SPACE$(PtrArray&(RightSide% + 1) - PtrArray&(RightSide%))
  183.  
  184.     GET #1, PtrArray&(RightSide%), Buffer$      'Read in a page
  185.  
  186.     IF INSTR(Buffer$, FF$) THEN                 'If the last character is a PF
  187.        PRINT #2, LEFT$(Buffer$, INSTR(Buffer$, FF$) - 1); 'print only text
  188.     ELSE
  189.        PRINT #2, Buffer$;                       'Otherwise print full line
  190.     END IF
  191.  
  192. NextPage:
  193.     IF PtrArray&(LeftSide% + 1) = 0 THEN        'Don't print blank pages
  194.        GOTO NextPage1
  195.     END IF
  196.     CALL DoMacro("1")                           'Reset margins for left side
  197.     LJLocate 0, 0                               'Home the cursor
  198.     IF PC.DoHeader THEN CALL Header(LeftSide%)  'Header if needed
  199.     Buffer$ = SPACE$(PtrArray&(LeftSide% + 1) - PtrArray&(LeftSide%))                'Setup buffer for input
  200.     IF LeftSide% = 0 THEN                       'If pointing at blank page, skip
  201.        GOTO NextPage1
  202.     END IF
  203.     GET #1, PtrArray&(LeftSide%), Buffer$       'Read in a page
  204.  
  205.     IF INSTR(Buffer$, FF$) THEN                 'if the last character is a PF
  206.        PRINT #2, LEFT$(Buffer$, INSTR(Buffer$, FF$) - 1); 'print only text
  207.     ELSE                                        'print only text
  208.        PRINT #2, Buffer$;                       'otherwise print all
  209.     END IF
  210.  
  211. NextPage1:
  212.     PRINT #2, FF$;                              'Page feed
  213.     LeftSide% = LeftSide - 2                    'Calculate next page in series
  214.     RightSide% = RightSide + 2
  215.     Bookmark% = Bookmark% - 1                   'Track our progress
  216.  
  217. LOOP UNTIL Bookmark% = 0                        'Print pages until halfway through
  218.  
  219. '============== Pause between sides
  220.     IF FirstPass THEN                           'If side one, prompt and get 2nd side
  221.        LOCATE , 1
  222.        PRINT "Insert paper back in tray and press Enter"
  223.        IF Tune% THEN BEEP
  224.  
  225. WaitKey:                                        'Press any key to continue loop
  226.     A$ = ""                                     'Set A$ = Null string - 0 length
  227.       DO
  228.         A$ = INKEY$                             'Get a key if one is pending
  229.       LOOP UNTIL LEN(A$)                        'Integer compares faster than strings
  230.       IF ASC(A$) = 27 THEN GOTO PrtReset        'ESC key, takes you out
  231.       IF ASC(A$) <> 13 THEN GOTO WaitKey        'Enter key only to prevent accidentally
  232.                                                 ' starting printer
  233.       FirstPass = 0                             'Flag for second pass
  234.       PRINT
  235.       PRINT "Printing Side 2 to "; OutFile$;    'Report on progress
  236.       GOTO DoPass
  237.     END IF                                      'End of first pass
  238.  
  239.     LOCATE , 1                                  'Printing is done now
  240.     PRINT "Printing completed "; SPACE$(60)
  241.     IF Tune% THEN BEEP
  242.  
  243. PrtReset:
  244.     PRINT #2, ESC$; "E";                        'Reset laserjet
  245.  
  246. OutHere:
  247.     CLOSE                                       'Close all files
  248. END                                             'Thats all for now
  249.  
  250. '============== Error handler
  251. ErrorDept:
  252.        PRINT
  253.        PRINT "*** Error ***"
  254.        BEEP
  255.    SELECT CASE ERR
  256.       CASE 24
  257.          PRINT ERDEV$; " timed out"
  258.       CASE 25                                   'Device fault
  259.          PRINT "Device Fault on "; ERDEV$
  260.       CASE 27                                   'Paper is out
  261.          PRINT "Out of paper on "; ERDEV$
  262.       CASE 53                                   'Source file not there
  263.          PRINT "File "; FileName$; " not found"
  264.          FileName$ = ""
  265.          GOSUB AWayOut
  266.          RESUME GetName
  267.       CASE 71                                   'Open drive door
  268.          PRINT "Disk drive "; ERDEV$; " not ready"
  269.       CASE ELSE
  270.          PRINT "Error number "; ERR
  271.          IF LEN(ERDEV$) THEN PRINT ERDEV$
  272.     END SELECT
  273.          GOSUB AWayOut
  274.          RESUME
  275.  
  276. AWayOut:
  277.    PRINT
  278.    PRINT "Press any key to try again"
  279.    PRINT "Or ESC to quit"
  280.    PRINT
  281.  
  282. KeyIn:                                          'Wait on error for a key
  283.    A$ = ""
  284.    DO
  285.       A$ = INKEY$
  286.    LOOP UNTIL LEN(A$)
  287.       IF ASC(A$) = 27 THEN                      'Exit out if ESC is pressed
  288.          CLOSE
  289.          END
  290.       END IF
  291. RETURN
  292.  
  293. '============================ End of main module ============================
  294.  
  295. SUB BuildArray (PtrArray&(), Pgcount%) STATIC
  296.    'FileName$ is shared from the main module
  297.  
  298.    MaxLines% = 66                               'Maximum number of lines
  299.    Offset& = 1                                  'Start of file (seek point)
  300.    OPEN FileName$ FOR BINARY AS #1 LEN = 1      'Open file to check
  301.    TotalSize& = LOF(1)                          'Get LEN of file so we don't read too far
  302.    FileLeft& = TotalSize&                       'Setup a counter to show whats left
  303.    MemAvail& = FRE(FileName$) - 2048            'Check available string memory
  304.    IF MemAvail& < 2048 THEN ERROR 14            'Force out of memory error
  305.    SixteenK% = 16384
  306.  
  307.    IF TotalSize& > SixteenK% THEN               'Set a buffer size
  308.       IF MemAvail& > SixteenK% THEN             'If the file is larger than 16K
  309.          BufSize& = SixteenK%                   'Set it to 16k
  310.       ELSE
  311.          BufSize% = MemAvail&
  312.       END IF
  313.    ELSE
  314.       IF TotalSize& < MemAvail& THEN            'Otherwise set it to file size
  315.          BufSize& = TotalSize&
  316.       END IF
  317.    END IF
  318.  
  319.    Pgcount% = 1                                 'Initialize page count
  320.    PtrArray&(Pgcount%) = 1                      'First pointer is always 1
  321.    LnCount% = 0                                 'Initialize line count
  322.  
  323. GetPage:
  324.                                                 'Read the file
  325.   IF FileLeft& < BufSize& THEN                  'Check amount left to read
  326.      Buffer$ = SPACE$(FileLeft&)                'If less than our buffer, use lessor
  327.   ELSE
  328.      Buffer$ = SPACE$(BufSize&)                 'Otherwise use full buffer size
  329.   END IF
  330.  
  331.   GET #1, Offset&, Buffer$                      'Read in a buffers worth
  332.   StPtr% = 1                                    'Pointer into buffer$
  333.   LastLine% = 0                                 'remember last position
  334.  
  335. PageCheck:
  336.   TempLn% = INSTR(StPtr%, Buffer$, LF$)         'Position of next linefeed
  337.   TempPg% = INSTR(StPtr%, Buffer$, FF$)         'Position of next pagefeeds
  338.  
  339.   IF TempPg% THEN                               'If there was a page feed
  340.      IF TempPg% < TempLn% OR TempLn% = 0 THEN   '  was it before our linefeed?
  341.         Pgcount% = Pgcount% + 1                 '  yes then bump page count
  342.         PtrArray&(Pgcount%) = Offset& + TempPg% '  set next array element
  343.         StPtr% = TempPg% + 1                    '  set instr pointer
  344.         LnCount% = 0                            '  reset linecount
  345.         IF StPtr% < LEN(Buffer$) THEN GOTO PageCheck 'and loop back for more
  346.       END IF
  347.   END IF
  348.  
  349.   IF TempLn% THEN                               'Linefeed
  350.      IF PC.LineWrap THEN                        'If /W the check line length
  351.         IF TempLn% - StPtr% > PC.LineLen THEN   'Greater than 80?
  352.            DO                                   'check for line wrap
  353.              LnCount% = LnCount% + 1            'increment line
  354.              IF LnCount% = MaxLines THEN GOTO PageBreak  '> 66 lines
  355.              StPtr% = StPtr% + PC.LineLen
  356.            LOOP WHILE TempLn% - StPtr% > PC.LineLen
  357.         END IF
  358.      END IF
  359.      LnCount% = LnCount% + 1                    'Increment page count
  360.  
  361. PageBreak:
  362.      IF LnCount% = MaxLines% THEN
  363.          Pgcount% = Pgcount% + 1
  364.             IF Pgcount% > 512 THEN
  365.                PRINT "Too may pages- printing only 512"
  366.                GOTO EndBuild
  367.             END IF
  368.          PtrArray&(Pgcount%) = Offset& + TempLn% 'point to next in point in file
  369.          LnCount% = 0
  370.      END IF
  371.      StPtr% = TempLn% + 1                       'point ahead 1 byte for next scan
  372.  
  373.      IF StPtr% <= LEN(Buffer$) THEN
  374.         GOTO PageCheck                          'keep checking
  375.      END IF
  376.   END IF
  377.  
  378.   Offset& = Offset& + LEN(Buffer$)              'Pointer into file (tally)
  379.   StPtr% = 1                                    'Reset Buffer pointer
  380.   FileLeft& = TotalSize& - Offset&              'Calculate how much is left
  381.   IF Offset& < TotalSize& THEN GOTO GetPage     'If more text in file, keep going
  382.  
  383. EndBuild:
  384.   PtrArray&(Pgcount% + 1) = TotalSize&          'Set last pointer to end of file
  385.  
  386. CLOSE #1                                        'Close input file
  387.  
  388. END SUB                                         'End of BuildArray Module
  389.  
  390. SUB DoMacro (Num$) STATIC
  391.     PRINT #2, ESC$; "&f"; Num$; "y2X";          'execute the macro
  392. END SUB
  393.  
  394. SUB EndMacro (Num$) STATIC
  395.     PRINT #2, ESC$; "&f"; Num$; "y1X";          'Send end of macro command
  396.     PRINT #2, ESC$; "&f"; Num$; "y9X";          'Make it temporary (10 to be permanent)
  397. END SUB
  398.  
  399. SUB Header (Page%) STATIC
  400.    Hdr$ = SPACE$(PC.LineLen)                    'Create a string to print
  401.    IF PC.FileTitle THEN                         'Print the filename
  402.       MID$(Hdr$, 40 - LEN(FileName$) \ 2) = UCASE$(FileName$)
  403.    END IF
  404.  
  405.    IF PC.PgNumber THEN                          'Print the current page
  406.      PTemp$ = "Page" + STR$(Page%)
  407.      IF Page% MOD 2 THEN
  408.         MID$(Hdr$, PC.LineLen - LEN(PTemp$)) = PTemp$ 'odd page, right side
  409.      ELSE
  410.         MID$(Hdr$, 1) = PTemp$                  'even page, left side
  411.      END IF
  412.    END IF
  413.  
  414.    IF PC.CurDate THEN                           'Print the current date
  415.      IF Page% MOD 2 THEN
  416.         MID$(Hdr$, 1) = DATE$                   'even page, left side
  417.      ELSE
  418.          MID$(Hdr$, PC.LineLen - LEN(DATE$)) = DATE$ 'odd page, right side
  419.      END IF
  420.    END IF
  421.    PRINT #2, Hdr$                               'Print the Header
  422.    PRINT #2,                                    ' and skip a line for readability
  423.  
  424. END SUB
  425.  
  426. SUB LJLocate (X%, Y%) STATIC                    'Laser Jet cursor locate
  427.     Temp$ = ESC$ + "&a" + LTRIM$(STR$(Y%)) + "r" + LTRIM$(STR$(X%)) + "C"
  428.     PRINT #2, Temp$;
  429. END SUB
  430.  
  431. SUB PrintLogo STATIC                            'Banner logo
  432. PRINT STRING$(80, 61)
  433. PRINT "PCBook - PC Magazine Booklet Printing Utility"
  434. PRINT "Copyright 1990 PC Magazine  Ziff Davis  Jay Munro"
  435. PRINT STRING$(80, 61)
  436. END SUB
  437.  
  438. SUB PrintSetup                  '============== Send codes to prepare printer
  439.     PRINT #2, ESC$; "E";                        'Reset laserjet (simple isn't it!)
  440.     PRINT #2, ESC$; "&l1o5.45C";                'Select lineprinter font"
  441.     PRINT #2, ESC$; "(s0p16.66H";               '  and pitch
  442.     PRINT #2, ESC$; "&l0L";                     'Turn off page feed at 66 lines
  443.  
  444.     IF PC.LineWrap THEN                         'Wrap lines > 80 chars
  445.        PRINT #2, ESC$; "&s0C";
  446.     END IF
  447.  
  448.     PRINT #2, ESC$; "&l2E";                     'Top margin 2 lines
  449.  
  450.     CALL StartMacro("1")                        'Left side macro
  451.          PRINT #2, ESC$; "9";                   'Reset left - right margins
  452.          PRINT #2, ESC$; "&a0l80M";             'set left margin 0, right 80
  453.     CALL EndMacro("1")
  454.  
  455.     CALL StartMacro("2")                        'Right side macro
  456.          PRINT #2, ESC$; "9";                   'Reset left - right margins
  457.          PRINT #2, ESC$; "&a95l175M";           'set left margin 95, right 175
  458.     CALL EndMacro("2")
  459.  
  460. END SUB
  461.  
  462. SUB StartMacro (Num$) STATIC
  463.     PRINT #2, ESC$; "&f"; Num$; "Y";            'Macro will have an id of Num$
  464.     PRINT #2, ESC$; "&f0X";                     'Start the macro now
  465. END SUB
  466.  
  467.